package com.franklin.ideaplugin.easytesting.ui;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import com.franklin.ideaplugin.api.ui.AbstractComponent;
import com.franklin.ideaplugin.api.ui.editor.CustomEditor;
import com.franklin.ideaplugin.api.ui.editor.FormatJsonButton;
import com.franklin.ideaplugin.api.utils.PsiUtil;
import com.franklin.ideaplugin.api.utils.UiUtils;
import com.franklin.ideaplugin.easytesting.cache.EasyTestingCache;
import com.franklin.ideaplugin.easytesting.rpc.RegistryCenter;
import com.franklin.ideaplugin.easytesting.rpc.RpcClient;
import com.franklin.ideaplugin.easytesting.rpc.entity.MethodInvokeData;
import com.franklin.ideaplugin.easytesting.rpc.entity.MethodParameter;
import com.franklin.ideaplugin.easytesting.rpc.entity.RegistryData;
import com.franklin.ideaplugin.easytesting.thread.EasyTestingThreadPool;
import com.franklin.ideaplugin.easytesting.utils.PsiUtils;
import com.franklin.ideaplugin.easytesting.utils.SwingUtils;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.openapi.ui.popup.PopupStep;
import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiParameter;
import com.intellij.psi.PsiType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.JBTextField;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author Ye Junhui
 * @since 2023/5/12
 */
public class RunMethodForm extends AbstractComponent {
    private JPanel mainPanel;
    private JPanel upPanel;
    private JButton executeBtn;
    private JPanel paramPanel;
    private JPanel headerPanel;
    private JPanel methodParamPanel;

    private PsiMethod psiMethod;

    private Runnable cancelWorker;

    /**
     * 缓存填充值
     */
    private Map<String, JComponent> paramMap;
    private Map<String, PsiParameter> psiParamMap;
    private Map<String,MethodParameter> executeParamMap;

    private CustomEditor headerEditor;

    public RunMethodForm(PsiMethod psiMethod) {
        this.psiMethod = psiMethod;
        this.paramMap = new LinkedHashMap<>();
        this.psiParamMap = new LinkedHashMap<>();
        this.init();
    }

    public void setCancelWorker(Runnable runnable){
        this.cancelWorker = runnable;
    }

    /**
     * 初始化
     */
    private void init(){
        initHeaderPanel();
        initMethodParamPanel();
        initExecuteBtn();
    }

    private void initHeaderPanel(){
        headerPanel.setLayout(SwingUtils.createLayoutManager(1,3));
        //标题
        this.addCell(headerPanel,new JBLabel("Http Header"),0,0,Sizes.RunMethodFormSize.CHILD_SIZE);


        //编辑器
        headerEditor = new CustomEditor(psiMethod.getProject(), CustomEditor.JSON_FILE_TYPE);
        String text = JSON.toJSONString(EasyTestingCache.getHeaderMap(psiMethod.getProject()), JSONWriter.Feature.PrettyFormat);
        headerEditor.setText(text);
        this.addCell(headerPanel,headerEditor,0,2,Sizes.RunMethodFormSize.HEADER_LABEL_SIZE);

        //格式化按钮
        FormatJsonButton formatJsonButton = new FormatJsonButton(headerEditor);
        this.addCell(headerPanel,formatJsonButton,0,1,Sizes.RunMethodFormSize.BTN_SIZE);

    }

    /**
     * 方法参数
     */
    private void initMethodParamPanel(){
        //方法参数
        List<PsiParameter> psiParameterList = PsiUtils.getPsiMethodParameters(psiMethod);
        if (CollectionUtil.isNotEmpty(psiParameterList)) {
            methodParamPanel.setLayout(SwingUtils.createLayoutManager(psiParameterList.size(),3));
        }

        //参数表单
        Map<String, Object> historyParamMap = getHistoryParamMap();
        for (int i = 0; i < psiParameterList.size(); i++) {
            PsiParameter psiParameter = psiParameterList.get(i);
            //参数名
            String label = "   "
                    + psiParameter.getType().getPresentableText()
                    + "   "
                    + psiParameter.getName();
            JBLabel jbLabel = new JBLabel(
                    UiUtils.splitLine(label,Sizes.RunMethodFormSize.CHILD_SIZE.width)
            );
            this.addCell(methodParamPanel, jbLabel,i,0,Sizes.RunMethodFormSize.CHILD_SIZE);

            //参数输入框
            //添加默认值
            Object defaultValue = historyParamMap.getOrDefault(psiParameter.getName(),PsiUtil.getDefaultValueOfPsiType(psiParameter.getType()));
            JComponent textField = null;
            if (Objects.isNull(defaultValue)){
                defaultValue = "";
            }
            String typeStr = psiParameter.getType().getCanonicalText();
            if (typeStr.contains("<")){
                int indexL = typeStr.indexOf("<");
                typeStr = typeStr.substring(0,indexL);
            }
            if (defaultValue instanceof Map || defaultValue instanceof Collection){
                textField = new CustomEditor(psiParameter.getProject(),CustomEditor.JSON_FILE_TYPE);
                CustomEditor customEditor = (CustomEditor) textField;
                String text = JSON.toJSONString(defaultValue, JSONWriter.Feature.PrettyFormat);
                customEditor.setText(text);
            }
            else if (defaultValue instanceof String){
                String str = (String) defaultValue;
                if (JSON.isValidObject(str)){
                    textField = new CustomEditor(psiParameter.getProject(),CustomEditor.JSON_FILE_TYPE);
                    CustomEditor customEditor = (CustomEditor) textField;
                    customEditor.setText(str);
                }else {
                    textField = new JBTextField();
                    JBTextField jbTextField = (JBTextField) textField;
                    String text = defaultValue.toString();
                    jbTextField.setText(text);
                }
            } else {
                textField = new JBTextField();
                JBTextField jbTextField = (JBTextField) textField;
                String text = defaultValue.toString();
                jbTextField.setText(text);
            }
            this.paramMap.put(psiParameter.getName(),textField);
            this.psiParamMap.put(psiParameter.getName(),psiParameter);

            if (textField instanceof CustomEditor){
                CustomEditor customEditor = (CustomEditor) textField;
                this.addCell(methodParamPanel,new FormatJsonButton(customEditor),i,1,Sizes.RunMethodFormSize.BTN_SIZE);
            }
            this.addCell(methodParamPanel,textField,i,2,Sizes.RunMethodFormSize.CHILD_SIZE);
        }
    }

    /**
     * 执行按钮
     */
    private void initExecuteBtn(){
        //点击执行
        this.executeBtn.addActionListener(e -> {
            Map<String, Object> historyParamMap = getHistoryParamMap();
            if (CollectionUtil.isNotEmpty(paramMap)){
                executeParamMap = new LinkedHashMap<>();
                historyParamMap.clear();
                paramMap.forEach((k,textField) -> {
                    String text = "";
                    if (textField instanceof JTextField){
                        JTextField field = (JTextField) textField;
                        text = field.getText();
                    }else if (textField instanceof CustomEditor){
                        CustomEditor customEditor = (CustomEditor) textField;
                        text= customEditor.getText();
                    }
                    historyParamMap.put(k,text);
                    PsiParameter psiParameter = psiParamMap.get(k);
                    executeParamMap.put(k,new MethodParameter(psiParameter.getType().getCanonicalText(),text));
                });
            }
            //获取端口
            List<RegistryData> registryDataList = RegistryCenter.getRegisterServer(psiMethod);
            if (CollectionUtil.isEmpty(registryDataList)){
                this.cancelWorker.run();
                return;
            }

            AtomicReference<RegistryData> registryDataHolder = new AtomicReference<>();
            if (registryDataList.size() == 1){
                registryDataHolder.set(registryDataList.get(0));
            }

            RegistryData registryData = registryDataHolder.get();
            if (Objects.isNull(registryData)){
                //弹窗
                this.chooseRegistryData(registryDataList,registryDataHolder);
            }else {
                doExecute(registryData);
            }

        });
    }

    @Override
    public JComponent getMainPanel() {
        return this.mainPanel;
    }

    private Map<String,String> getHeaderMap(){
        String headerJson = this.headerEditor.getText();
        Map<String, String> headerMap = EasyTestingCache.getHeaderMap(psiMethod.getProject());
        try {
            JSONObject jsonObject = JSON.parseObject(headerJson);
            headerMap.clear();
            jsonObject.forEach((k,v) -> headerMap.put(k,v.toString()));
        } catch (Exception exception) { }
        return headerMap;
    }

    private Map<String,Object> getHistoryParamMap(){
        return EasyTestingCache.getHistoryParamMap(psiMethod);
    }

    /**
     * 获取数据
     * @param registryDataList
     * @return
     */
    private void chooseRegistryData(List<RegistryData> registryDataList,AtomicReference<RegistryData> registryDataHolder){
        ListPopup listPopup = JBPopupFactory.getInstance().createListPopup(
                new BaseListPopupStep<>(
                        "Choose The Running App",
                        registryDataList
                ) {


                    @Override
                    public @NotNull String getTextFor(RegistryData value) {
                        return value.getAppName();
                    }

                    @Override
                    public @Nullable PopupStep<?> onChosen(RegistryData selectedValue, boolean finalChoice) {
                        doExecute(selectedValue);
                        return PopupStep.FINAL_CHOICE;
                    }


                }
        );
        listPopup.showCenteredInCurrentWindow(psiMethod.getProject());
    }

    private void doExecute(RegistryData registryData){
        EasyTestingThreadPool.getBizThreadPool().execute(() -> {
            ApplicationManager.getApplication().runReadAction(() -> {
                MethodInvokeData methodInvokeData = new MethodInvokeData();
                methodInvokeData.setClassQualifiedName(PsiTreeUtil.getParentOfType(psiMethod, PsiClass.class).getQualifiedName());
                methodInvokeData.setMethodName(psiMethod.getName());
                methodInvokeData.setParameterMap(executeParamMap);
                methodInvokeData.setHeaderMap(getHeaderMap());

                RpcClient.sendExecute(methodInvokeData, registryData.getPort());
            });
        });
        cancelWorker.run();
    }
}
